package org.softee.concurrent;

import static java.math.BigInteger.ONE;

import java.math.BigInteger;

public class Factorial {
    public static class FactorialResult {
        public final BigInteger number;
        public final BigInteger factorial;

        private FactorialResult(BigInteger number, BigInteger factorial) {
            this.number = number;
            this.factorial = factorial;
        }

        @Override
        public String toString() {
            return number + "! = " + factorial;
        }

        public static FactorialResult valueOf(long number) {
            return valueOf(BigInteger.valueOf(number));
        }

        public static FactorialResult valueOf(BigInteger number) {
            return new FactorialResult(number, factorial(number));
        }

    }

    /** Recursive implementation of factorial algorithm made slow by using BigInteger
     * @param number the number to factorialize
     * @return the factorial of {@code number}
     */
    public static BigInteger factorial(long number) {
        return factorial(BigInteger.valueOf(number));
    }

    /** Recursive implementation of factorial algorithm made slow by using BigInteger
     * @param number the number to factorialize
     * @return the factorial of {@code number}
     */
    public static BigInteger factorial(BigInteger number) {
      if (number.compareTo(BigInteger.ONE) <= 0) { // number <= 1
        return BigInteger.ONE; // 0! => 1, 1! => 1
      } else {
        return number.multiply(factorial(number.subtract(ONE)));
      }
    }
}
